﻿using System.Collections.Generic;
using System.Linq;
using Analyze.Calculator;
using Common.Dao;
using Common.Extension;
using Common.Model;
using log4net;

namespace Analyze.Provider
{
    public class TrainingDataProvider
    {
        private static readonly ILog Log = LogManager.GetLogger(typeof(TrainingDataProvider));

        private static readonly object Lock = new object();

        private static volatile TrainingDataProvider _instance;

        private readonly List<DxwEvent> _events;
        private readonly List<ClassifyModel> _models;

        private readonly Dictionary<string, float> _blockWordDictionary;
        private readonly Dictionary<string, int> _blockCountDictionary;

        public readonly int BlockCount;

        public static TrainingDataProvider GetInstance()
        {
            if (null == _instance)
            {
                lock (Lock)
                {
                    if (null == _instance)
                    {
                        _instance = new TrainingDataProvider();
                    }
                }
            }
            return _instance;
        }

        public List<ClassifyModel> GetClassifyModels()
        {
            return _models;
        }

        public void Reload()
        {
            if (null != _instance)
            {
                lock (Lock)
                {
                    if (null != _instance)
                    {
                        _instance = null;
                    }
                }
            }
            GetInstance();
        }


        public List<ClassifyModel> GetClassifyModelByBlockAndWord(string block, string word)
        {
            return ClassifyModelDao.GetClassifyModelByBlockWord(block, word);
        }

        public List<ClassifyModel> GetClassifyModelsByBlock(string block)
        {
            return _models.Where(m => m.Block.Equals(block)).ToList();
        }

        private TrainingDataProvider()
        {
            _events = DxwEventDao.GetEventsWithWords();

            List<string> blocks = _events.Select(m => m.Block).Distinct().ToList();

            List<string> dropedBlocks = NewBlockDao.GetNewBlocksDroped()?.Select(m => m.BlockName).ToList();

            if (null != dropedBlocks && dropedBlocks.Count > 0)
            {
//                foreach (var dropedBlock in dropedBlocks)
//                {
//                    _events = _events.Where(m => !m.Block.Equals(dropedBlock)).ToList();
//                }
                blocks = blocks.Except(dropedBlocks).ToList();
            }

            _models = ClassifyModelDao.GetClassifyModel();

            if (null == _models || _models.Count == 0)
            {
                _blockCountDictionary = new Dictionary<string, int>();
                foreach (var block in blocks)
                {
                    if (!string.IsNullOrEmpty(block))
                    {
                        _blockCountDictionary.Add(block, _events.Count(m => m.Block.EndsWith(block)));
                    }
                }
            }
            else
            {
                _blockWordDictionary =
                    _models.ToDictionary(m => m.Block + ":" + m.Word, m => m.WordConditionaProbability);
                List<string> traningClassifications = _GetTraningClassificationsModes();
                _blockCountDictionary =
                    traningClassifications.ToDictionary(m => m, _GetTrainingCountOfClassification);
                BlockCount = blocks.Count();
            }
        }

        public float GetWordConditionaProbability(string block, string word)
        {
            string key = block + ":" + word;
            if (_blockWordDictionary.ContainsKey(key))
            {
                return _blockWordDictionary.Get(key);
            }

            return Probability.NullConditionalProbability(block);
        }

        /// <summary>
        /// 返回训练文本类别集合，即板块集合
        /// </summary>
        /// <returns></returns>
        public List<string> GetTraningClassifications()
        {
            return _blockCountDictionary.Keys.ToList();
        }

        /// <summary>
        /// 返回训练文本类别集合，即板块集合
        /// </summary>
        /// <returns></returns>
        private List<string> _GetTraningClassificationsModes()
        {
            return _models.Select(m => m.Block).Distinct().ToList();
        }

        /**
        * 返回给分类的分词集合
        * @param block 给定的文本分类
        * @return 文本内容
        */
        public List<string> GetWords(string block)
        {
            return _events.Where(m => block.Equals(m.Block)).Select(m => m.Content).ToList();
        }

        /**
        * 返回训练文本集中所有的文本数目
        * @return 训练文本集中所有的文本数目
        */
        public int GetTrainngCount()
        {
            return _events.Count;
        }

        /**
        * 返回训练文本集中在给定分类下的训练文本数目
        * @param block 给定的分类
        * @return 训练文本集中在给定分类下的训练文本数目
        */

        private int _GetTrainingCountOfClassification(string block)
        {
            return _events.Count(m => block.Equals(m.Block));
        }

        public int GetTrainingCountOfClassification(string block)
        {
            return _blockCountDictionary.Get(block);
        }

        /**
        * 返回给定分类中包含关键字／词的训练文本的数目
        * @param block 给定的分类
        * @param keyWord 给定的关键字／词
        * @return 给定分类中包含关键字／词的训练文本的数目
        */
        public int GetCountContainKeyOfClassification(string block, string keyWord)
        {
            return _events.Count(m => block.Equals(m.Block) && (m.Title + m.Content ?? "").Contains(keyWord));
        }
    }
}